/*
 * Copyright (c) 2015-2018 Sfkj Science And Technology Co.,Ltd.
 * All Rights Reserved.
 * This software is the confidential and proprietary information of
 * Sfkj Science And Technology Co.,Ltd.
 * ("Confidential Information").You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Sfkj.
 */
package com.sfkj.walk.command.user;

import com.google.common.base.Preconditions;
import com.querydsl.core.BooleanBuilder;
import com.sfkj.walk.api.query.user.SocialAccountOneByPredicateQuery;
import com.sfkj.walk.api.user.*;
import com.sfkj.walk.query.user.QSocialAccount;
import com.sfkj.walk.query.user.SocialAccount;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.axonframework.commandhandling.CommandHandler;
import org.axonframework.commandhandling.model.AggregateIdentifier;
import org.axonframework.eventsourcing.EventSourcingHandler;
import org.axonframework.queryhandling.QueryGateway;
import org.axonframework.spring.stereotype.Aggregate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.Objects;

import static com.sfkj.walk.Contants.CACHE_CAPTCHA_NAME;
import static org.axonframework.commandhandling.model.AggregateLifecycle.apply;

@NoArgsConstructor(access = AccessLevel.PUBLIC)
@Getter
@Aggregate
public class User {

    @Autowired
    private QueryGateway queryGateway;

    @AggregateIdentifier
    private String id;
    private String password;

    @CommandHandler
    public User(RegisterPhoneUserCommand command, PasswordEncoder passwordEncoder,
                CacheManager cacheManager,
                QueryGateway queryGateway) {
        Preconditions.checkState(check(SocialAccountType.PHONE, command.getPhone(), queryGateway), "手机号码已被注册");

        String captcha = cacheManager.getCache(CACHE_CAPTCHA_NAME).get(command.getPhone(), String.class);
        Preconditions.checkState(Objects.equals(captcha, command.getCaptcha()), "手机验证码不正确");

        {
            PhoneUserRegisteredEvent event = new PhoneUserRegisteredEvent();
            BeanUtils.copyProperties(command, event);
            apply(event);
        }

        {
            UserPasswordChangedEvent event = new UserPasswordChangedEvent();
            event.setId(command.getId());
            event.setPassword(passwordEncoder.encode(command.getPassword()));
            apply(event);
        }
    }

    public boolean authenticate(String password, PasswordEncoder passwordEncoder) {
        boolean success = passwordEncoder.matches(password, this.password);
        if (success) {
            apply(new AuthenticatedEvent(this.id));
        }

        return success;
    }

    private boolean check(SocialAccountType socialAccountType, String openId, QueryGateway queryGateway) {
        BooleanBuilder conditions = new BooleanBuilder();
        conditions.and(QSocialAccount.socialAccount.socialAccountType.eq(socialAccountType));
        conditions.and(QSocialAccount.socialAccount.openId.eq(openId));

        SocialAccountOneByPredicateQuery query = new SocialAccountOneByPredicateQuery();
        query.setPredicate(conditions);

        SocialAccount socialAccount = queryGateway.send(query, SocialAccount.class).getNow(null);
        return Objects.isNull(socialAccount);
    }

    @EventSourcingHandler
    public void on(PhoneUserRegisteredEvent event) {
        this.id = event.getId();
    }

    @EventSourcingHandler
    public void on(UserPasswordChangedEvent event) {
        this.password = event.getPassword();
    }

}